﻿/*
Copyright (c) 2009 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System;
using System.Collections.Generic;
using System.IO;
using TeachMe.Application.Exceptions;

namespace TeachMe.Application
{
    public class PathsProvider
    {
        private class Comparer : IComparer<Pair<string, string>>
        {
            public int Compare(Pair<string, string> x, Pair<string, string> y)
            {
                return y.Value.Length - x.Value.Length;
            }
        }

        private readonly string _priorities;
        private readonly string _machineSettings;
        private readonly string _userSettings;
        private readonly string _importExcludes;

        private static readonly List<Pair<string, string>> Directories = new List<Pair<string, string>>();

        static PathsProvider()
        {
            FillDirectories();
        }

        private static void FillDirectories()
        {
            string[] variables = new[]
                                     {
                                         "%ApplicationData%", "%CommonApplicationData%", "%LocalApplicationData%",
                                         "%Favorites%", "%Programs%", "%MyComputer%", "%MyMusic%", "%MyPictures%", "%System%", 
                                         "%DesktopDirectory%", "%MyDocuments%", "%ProgramFiles%", "%CommonProgramFiles%"
                                     };

            foreach (string variable in variables)
            {
                Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), variable.Trim('%'));
                string directory = Environment.GetFolderPath(specialFolder);

                if (String.IsNullOrEmpty(directory))
                {
                    continue;
                }

                Directories.Add(new Pair<string, string>(variable, directory));
            }

            Directories.Add(new Pair<string, string>("%TeachMe%", Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)));
            
            Directories.Sort(new Comparer());
        }

        public PathsProvider()
        {
            string appDir = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
            string configurationPath = Path.Combine(appDir, "Configuration.xml");

            if (File.Exists(configurationPath))
            {
                try
                {
                    XmlEditor editor = XmlEditor.Load(configurationPath);

                    if (editor.HasChildNode("Priorities"))
                    {
                        using (editor.LoadNode("Priorities"))
                        {
                            _priorities = MakeTransient(editor.GetTextValue());
                        }
                    }

                    if (editor.HasChildNode("MachineSettings"))
                    {
                        using (editor.LoadNode("MachineSettings"))
                        {
                            _machineSettings = MakeTransient(editor.GetTextValue());
                        }
                    }

                    if (editor.HasChildNode("UserSettings"))
                    {
                        using (editor.LoadNode("UserSettings"))
                        {
                            _userSettings = MakeTransient(editor.GetTextValue());
                        }
                    }

                    if (editor.HasChildNode("ImportExcludes"))
                    {
                        using (editor.LoadNode("ImportExcludes"))
                        {
                            _importExcludes = MakeTransient(editor.GetTextValue());
                        }
                    }
                }
                catch (XmlEditorException)
                {

                }
            }

            if (String.IsNullOrEmpty(_priorities))
            {
                _priorities = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TeachMe");
            }
            if (String.IsNullOrEmpty(_machineSettings))
            {
                _machineSettings = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TeachMe\\MachineSettings.xml");
            }
            if (String.IsNullOrEmpty(_userSettings))
            {
                _userSettings = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TeachMe\\UserSettings.xml");
            }
            if (String.IsNullOrEmpty(_importExcludes))
            {
                _importExcludes = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TeachMe\\ImportExcludes.xml");
            }

            EnsureDirectory(_priorities);
            EnsureDirectory(Path.GetDirectoryName(_userSettings));
            EnsureDirectory(Path.GetDirectoryName(_machineSettings));
            EnsureDirectory(Path.GetDirectoryName(_importExcludes));
        }

        private static void EnsureDirectory(string directory)
        {
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
        }

        public static string MakeTransient(string persistentPath)
        {
            // 13.03.2010 - several users reported crash when program is being loaded, this was caused by
            // exception thrown at the end of this method; somehow, invalid dictionary path is stored in
            // configuration file

            if (String.IsNullOrEmpty(persistentPath))
            {
                return persistentPath;
            }

            // if (Path.IsPathRooted(persistentPath))
            if (File.Exists(persistentPath))
            {
                return persistentPath;
            }

            foreach (Pair<string, string> pair in Directories)
            {
                if (persistentPath.StartsWith(pair.Key))
                {
                    return persistentPath.Replace(pair.Key, pair.Value);
                }
            }

            Logging.Error(typeof(PathsProvider), "Relative path '{0}' cannot be fixed.", persistentPath);

            // throw new ArgumentException();
            return persistentPath;
        }

        public static string MakePersistent(string relativePath)
        {
            if (String.IsNullOrEmpty(relativePath))
            {
                return relativePath;
            }

            foreach (Pair<string, string> pair in Directories)
            {
                int start, end;

                if (Find(relativePath, pair.Value, out start, out end))
                {
                    return relativePath.Substring(0, start) + pair.Key + relativePath.Substring(end);
                }
            }

            return relativePath;
        }

        private static bool Find(string where, string what, out int start, out int end)
        {
            where = where.ToLower();
            what = what.ToLower();

            start = where.IndexOf(what);
            end = start < 0 ? -1 : what.Length + start;

            return start >= 0;
        }

        public string Priorities
        {
            get { return _priorities; }
        }

        public string MachineSettings
        {
            get { return _machineSettings; }
        }

        public string UserSettings
        {
            get { return _userSettings; }
        }

        public string ImportExcludes
        {
            get { return _importExcludes; }
        }

        public string DefaultDictsFolder
        {
            get
            {
                return Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Dicts");
            }
        }

        public static string DefaultThemesFolder
        {
            get
            {
                return Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Themes");
            }
        }
    }
}